
package com.yadong.smarthome2.control;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import android.text.TextUtils;

import com.yadong.smarthome2.device.Device;
import com.yadong.smarthome2.device.DeviceManagerService;
import com.yadong.smarthome2.protocol2.ALog;
import com.yadong.smarthome2.protocol2.RequestProtocol.Parameter;
import com.yadong.smarthome2.protocol2.RequestProtocol.Request;
import com.yadong.smarthome2.protocol2.ResultProtocol.DeviceInfo.Status;

public class ControlRules {
    private Device mDevice;
    private List<Status> mStatuses;

    private String mMin;
    private String mMax;
    private String mJustRight;

    private Device mTargetDevice;
    private String mFunctionCode;
    private List<Parameter> mParameters;

    private ControlRules() {
    }

    public DoSomething createDoSomethingRunnable(DeviceManagerService
            deviceManagerService){
        return new DoSomething(deviceManagerService);
    }

    public class DoSomething implements Runnable {
        private DeviceManagerService mDeviceManagerService;

        public DoSomething(DeviceManagerService deviceManagerService) {
            this.mDeviceManagerService = deviceManagerService;
        }

        @Override
        public void run() {
            // We do not check the device state, we will do it at DeviceManagerService
            Request.Builder requestBuilder = Request.newBuilder();
            requestBuilder.addAllParameters(mParameters);
            requestBuilder.setTime(System.currentTimeMillis());
            requestBuilder.setTag(mFunctionCode);
            requestBuilder.addAllParameters(mParameters);

            mDeviceManagerService.sendData(mTargetDevice, requestBuilder.build());
        }
    }

    public List<Status> getStatuses() {
        return mStatuses;
    }

    public String getMin() {
        return mMin;
    }

    public String getMax() {
        return mMax;
    }

    public String getJustRight() {
        return mJustRight;
    }

    public Device getTargetDevice() {
        return mTargetDevice;
    }

    public String getFunctionCode() {
        return mFunctionCode;
    }

    public List<Parameter> getParameters() {
        return mParameters;
    }

    public static class RuleBuilder {
        private Device mDevice;
        private List<Status> mStatuses;

        private String mMin;
        private String mMax;
        private String mJustRight;

        private Device mTargetDevice;
        private String mFunctionCode;
        private List<Parameter> mParameters;

        public void setmDevice(Device mDevice) {
            this.mDevice = mDevice;
        }

        public void setmStatus(List<Status> statuses) {
            this.mStatuses = statuses;
        }

        public void addStatus(Status status) {
            if(mStatuses == null) {
                mStatuses = new ArrayList<Status>();
            }
            if (mStatuses.indexOf(status) == -1) {
                mStatuses.add(status);
            }
        }

        public void setmMin(String mMin) {
            this.mMin = mMin;
        }

        public void setmMax(String mMax) {
            this.mMax = mMax;
        }

        public void setmJustRight(String mJustRight) {
            this.mJustRight = mJustRight;
        }

        public void setmTargetDevice(Device mTargetDevice) {
            this.mTargetDevice = mTargetDevice;
        }

        public void setmDoFunction(String mDoFunction) {
            this.mFunctionCode = mDoFunction;
        }

        public void setmParameters(List<Parameter> mParameters) {
            this.mParameters = mParameters;
        }

        public void addParameter(Parameter parameter) {
            if (mParameters == null) {
                mParameters = new ArrayList<Parameter>();
            }
            if (mParameters.indexOf(parameter) == -1) {
                mParameters.add(parameter);
            }
        }

        public Device getmDevice() {
            return mDevice;
        }

        public List<Status> getmStatuses() {
            return mStatuses;
        }

        public String getmMin() {
            return mMin;
        }

        public String getmMax() {
            return mMax;
        }

        public String getmJustRight() {
            return mJustRight;
        }

        public Device getmTargetDevice() {
            return mTargetDevice;
        }

        public String getmFunctionCode() {
            return mFunctionCode;
        }

        public List<Parameter> getmParameters() {
            return mParameters;
        }

        public ControlRules build() {
            ControlRules rule = new ControlRules();
            // check device
            if (mTargetDevice == null || mDevice == null) {
                throw new RuntimeException("target device and device cant be null");
            } else {
                rule.mTargetDevice = mTargetDevice;
                rule.mDevice = mDevice;
            }
            // check min & max just right
            if (TextUtils.isEmpty(mMin) && TextUtils.isEmpty(mMax)) {
                if (TextUtils.isEmpty(mJustRight)) {
                    throw new RuntimeException("no rules drect");
                } else {
                    rule.mJustRight = mJustRight;
                    rule.mMin = null;
                    rule.mMax = null;
                }
            } else if (!TextUtils.isEmpty(mMin) && !TextUtils.isEmpty(mMax)) {
                rule.mJustRight = null;
                rule.mMin = mMin;
                rule.mMax = mMax;
            }
            // Function
            if (TextUtils.isEmpty(mFunctionCode)) {
                throw new RuntimeException("no function drect");
            } else {
                rule.mFunctionCode = mFunctionCode;
            }
            // Status
            if (mStatuses == null || mStatuses.size() <= 0) {
                throw new RuntimeException("no status drect");
            } else {
                rule.mStatuses = mStatuses;
            }
            // Argument
            if (mParameters == null || mParameters.size() <= 0) {
                throw new RuntimeException("no mParameters drect");
            } else {
                rule.mParameters = mParameters;
            }
            return rule;
        }
    }

    public Device getDevice() {
        return mDevice;
    }

    public boolean matchRule(Map<String, String> inputValues) {
        int matchedCount = 0;
        for (String keyValue : inputValues.keySet()) {
            for (Status status : mStatuses) {
                if (!status.getName().equals(keyValue)) {
                    continue;
                }
                String value = inputValues.get(keyValue);
                String dataType = status.getType();
                // digit data type
                if ("I".equals(dataType)
                        || "F".equals(dataType)
                        || "L".equals(dataType)
                        || "D".equals(dataType)) {
                    if (!TextUtils.isEmpty(mMin) && !TextUtils.isEmpty(mMax)) {
                        try {
                            double data = Double.parseDouble(value);
                            double min = Double.parseDouble(mMin);
                            double max = Double.parseDouble(mMax);
                            if (data >= min && data <= max) {
                                matchedCount++;
                            }
                        } catch (NumberFormatException exception) {
                            exception.printStackTrace();
                        }
                    } else if (!TextUtils.isEmpty(mJustRight)) {
                        try {
                            double data = Double.parseDouble(value);
                            double justRight = Double.parseDouble(mJustRight);
                            if (data == justRight) {
                                matchedCount++;
                            }
                        } catch (NumberFormatException exception) {
                            exception.printStackTrace();
                        }
                    }
                    ALog.loge(ControlRules.this, "Eror rule:" + this);
                } else if ("S".equals(dataType) || "B".equals(dataType)) {
                    if (TextUtils.isEmpty(mJustRight)) {
                        ALog.loge(ControlRules.this, "Eror string rule:" + this);
                    }
                    if(mJustRight.equals(value)) {
                        matchedCount++;
                    }
                }
            }
        }
        return matchedCount == mStatuses.size();
    }
}
